package com.virtual.repository.common.managers;

import java.util.HashMap;
import java.util.Map;

import com.virtual.repository.common.queries.Query;
import com.virtual.repository.plugins.api.IDatabasePlugin;

/**
 * Class stores information about query execution - which driver executes which query and 
 * what is expected result of it.
 * Hierarchical structure.
 *   
 * @author kchaber
 *
 */
public class QueryExecutionData {
	/**
	 * The plugin which is executing the query.
	 */
	private IDatabasePlugin executionPlugin;
	
	/**
	 * The query being executed.
	 */
	private Query executionQuery;
	
	/**
	 * The expected result object class
	 */
	private Class<?> expectedResultClass;
	
	/**
	 * The expected collection result class
	 */
	private Class<?> expectedCollectionResultClass;
	
	/**
	 * The field name in the parent Object, where the result of the query should be set
	 */
	private String parentObjectFieldName;
	
	/**
	 * The map containing all sub-queries connected with the root entity.
	 */
	private Map<String, QueryExecutionData> subExecutionData = new HashMap<>();

	/**
	 * Returns the query object used to retrieve entity identifier value.
	 * @return
	 */
	public Query getIdentificationQuery(String identifierFieldName) {
		Query identificationQuery = new Query();
		identificationQuery.setEntityName(this.executionQuery.getEntityName());
		identificationQuery.setSelectionCriteria(this.executionQuery.getSelectionCriteria());
		identificationQuery.addSelectionField(identifierFieldName);
		
		return identificationQuery;
	}
	
	/**
	 * @return <code>true</code> if execution data has some sub-queries or <code>false</code> when not.
	 */
	public boolean hasSubqueries() {
		if (this.subExecutionData == null || this.subExecutionData.isEmpty()) {
			return false;
		}
		
		return true;
	}
	
	/**
	 * @return <code>true</code> if execution data must return collection result or <code>false</code> when not.
	 */
	public boolean isCollectionResult() {
		return this.expectedCollectionResultClass != null;
	}
	
	public String getQueriesAsString() {
		String result = this.getExecutionQuery().toString() + " will be executed by: " + this.executionPlugin + " \n";
		
		if (this.subExecutionData != null) {
			for (QueryExecutionData subExec : this.subExecutionData.values()) {
				result += subExec.getQueriesAsString();
			}
		}
		
		return result;
	}
	
	public Query getExecutionQuery() {
		return executionQuery;
	}

	public void setExecutionQuery(Query executionQuery) {
		this.executionQuery = executionQuery;
	}

	public IDatabasePlugin getExecutionPlugin() {
		return executionPlugin;
	}

	public void setExecutionPlugin(IDatabasePlugin executionPlugin) {
		this.executionPlugin = executionPlugin;
	}

	public Class<?> getExpectedResultClass() {
		return expectedResultClass;
	}

	public void setExpectedResultClass(Class<?> expectedResultClass) {
		this.expectedResultClass = expectedResultClass;
	}

	public String getParentObjectFieldName() {
		return parentObjectFieldName;
	}

	public void setParentObjectFieldName(String parentObjectFieldName) {
		this.parentObjectFieldName = parentObjectFieldName;
	}

	public Map<String, QueryExecutionData> getSubExecutionData() {
		return subExecutionData;
	}

	public void setSubExecutionData(Map<String, QueryExecutionData> subExecutionData) {
		this.subExecutionData = subExecutionData;
	}

	public Class<?> getExpectedCollectionResultClass() {
		return expectedCollectionResultClass;
	}

	public void setExpectedCollectionResultClass(Class<?> expectedCollectionResultClass) {
		this.expectedCollectionResultClass = expectedCollectionResultClass;
	}
}
